package com.yinhai.tool;

import java.awt.Image;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

import org.apache.tools.zip.*;

import javax.swing.ImageIcon;
import javax.swing.filechooser.FileSystemView;

import sun.awt.shell.ShellFolder;

import com.yinhai.model.FileInfo;
/**
 * 
 * @author hp
 * purpose：该类主要用于文件系统操作相关的方法
 * create date:2010.01.11
 * last update:caizh
 */
public class FileTools {
	
	private FileTools(){} 
	private static FileTools instance=new FileTools();
	/**（单态）
	 * purpose 创建工具类实例
	 * @return 该文件工具类的实例
	 */
	public static FileTools getInstance(){
		return instance;
	}
	/**
	 * 
	 * @param File
	 * @return 根文件分区名称
	 */
	public String getDisplayName(File f){
		String fileName=null;
		if(f.exists())//分区获取名称
		{
		try {
			ShellFolder sf = ShellFolder.getShellFolder(f);
			fileName=sf.getDisplayName();
		} catch (FileNotFoundException e) {
			
			return fileName="-1";
		}
		}
		else //虚拟分区的名称
		{
			fileName=f.getPath().replaceAll("\\\\","/");
		}
		return fileName;
	}
	
	/**
	 * purpose 获取指定系统文件图标
	 * @param f
	 * @return 返回f对应的系统文件图标
	 */
	public Image getFileImage(File f){
	    FileSystemView fsv=FileSystemView.getFileSystemView();//FileSystemView 是 JFileChooser 的文件系统网关
		Image i=((ImageIcon)fsv.getSystemIcon(f)).getImage();//返回文件、目录或文件夹图标的 Image
//        BufferedImage bi=new BufferedImage(16,16,BufferedImage.TYPE_4BYTE_ABGR);//可访问图像数据缓冲区的 Image,即是在图像缓冲区分配一定内存空间
//        bi.createGraphics().drawImage(i,0,0,null);//获取画笔并绘制当前可用的图像
//		  OutputStream os=response.getOutputStream();//获取相应输出流
//        ImageIO.write(bi,"PNG",os);//使用支持给定格式的任意 ImageWriter 将一个图像写入 OutputStream
//        os.close();
        return i;
	}
	/**
	 * purpose 用于获取文件大小字符窜或者文件夹数目字符串
	 * @param f:文件或者目录
	 * @param isDirectory：是否是目录
	 * @return 文件大小字符窜或者文件夹数目字符串
	 */
	public String getFileSpace(File f)
	{
		String result=null;
		int space=0;

		if(f.exists())
		{
			if(f.isDirectory())//如果是目录则返回的是目录里面的文件夹数目
			{
				File[] files=f.listFiles();
				try
				{
					space=files.length;
				}catch(Exception e)
				{
					space=0;
				}
				 
				 result=space+" ";
			}
			else
			{
				DecimalFormat df=new DecimalFormat("#,##0.00");
				result=df.format(f.length()/1024F)+" KB";
			}
		}
		
		
		
		return result;
	}
	/**
	 * purpose:获取文件类型
	 * @param f:文件或者目录
	 * @param isRoot：是否是目录
	 * @return 文件的类型
	 */
	public String getFileType(File f){
		String fileType=null;
		ShellFolder sf = null;
		if(f.exists())
		{
			try {
				sf = ShellFolder.getShellFolder(f);
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		    fileType=sf.getFolderType();//获取文件类型
		}
		
		return fileType;
	}
	
	/**
	 * purpose 获取最后一次修改日期
	 * @param f
	 * @return 最后一次修改日期字符窜
	 */
	public String getModifyDate(File f)
	{
		String d=null;
		if(f.exists())
		{
			SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm");
			Long dl=f.lastModified();
			d=sdf.format(new Date(dl));
		}
		
		return d;
	}
	
	/**
	 * purpose 获取其返回此抽象路径名的绝对路径名字符串
	 * @param f
	 * @return application/x-www-form-urlencoded MIME 格式的字符窜
	 */
	public String getFileUrlPath(File f)
	{
		String path=null;
		try {
			path=URLEncoder.encode(f.getAbsolutePath(), "utf-8");
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return path;
	}
	
	public String getFileProperty(File f)
	{
		String result=null;
		String isHidden=null;
		String isRead=null;

	    if(!f.canWrite())
		{
			isRead="R(only read)";
			result=isRead;
		}
		if(f.isHidden())
		{
			isHidden="H(hidden)";
			result=isHidden;
		}
		if(!f.canWrite()&&f.isHidden()){
			result=isRead+" "+isHidden;
		}
		
	
		return result;
	}
	
	/**
	 * purpose 将文件数组分装成FileInfo,并装进容器
	 * @param fs
	 * @return 装有FileInfo的List
	 */
	public List returnFiles(File [] fs)
	{
		List s=new ArrayList();
		
		FileInfo fi=null;
		File f=null;
		for (int i=0;i<fs.length;i++)
		{
			f=(File)fs[i];
			fi=this.returnFileInfo(f);
			s.add(fi);
			f=null;
			fi=null;
		}
		return s;
	}
	
	public FileInfo returnFileInfo(File f)
	{
		FileInfo fi=new FileInfo();
		if(f.exists())
		{
			
			fi.setFileName(getDisplayName(f));
			fi.setFileSpace(getFileSpace(f));
			fi.setFileType(getFileType(f));
			fi.setModifyDate(getModifyDate(f));
			fi.setProperty(getFileProperty(f));
		}
		else
		{
			fi.setFileName(getDisplayName(f));
		}
		
		fi.setFilePath(getFileUrlPath(f));
		if(f.isFile())
		{
			fi.setIsFile("file");
		}
		return fi;
	}
	
	public boolean deleteFile(File f)
	{
		boolean b=false;
		if(f.isDirectory())
		{
			this.deleteDirFiles(f);
			this.deleteChildDir(f);
			b=f.delete();
		}
		else
		{
			b=f.delete();
		}
		
		return b;
	}
	/**
	 * purpose 删除目录中的所有文件
	 * @return
	 */
	public boolean deleteDirFiles(File f)
	{
		boolean b=false;
		if(f.isDirectory()&&f.listFiles()!=null)
		{
			
			File [] fs=f.listFiles();
			for(int i=0;i<fs.length;i++)
			{
				if(fs[i].isDirectory()){
					b=this.deleteDirFiles(fs[i]);
			    }
				else if(fs[i].isFile())
				{
					b=fs[i].delete();
				}
			}
			
		}
		
		return b;
	}
	
	/**
	 *  purpose 删除目录下所有子目录
	 */
	public boolean deleteChildDir(File f)
	{
		boolean b=false;
		if(f.isDirectory())
		{
			
			File [] fs=f.listFiles();
			if(fs.length<1)
			{
				f.delete();
			}
			else
			{
				for(int i=0;i<fs.length;i++)
				{
					if(fs[i].listFiles()!=null&&fs[i].isDirectory()){
						b=this.deleteChildDir(fs[i]);
					}
					else if(fs[i].listFiles()==null&&fs[i].isDirectory())
					{
						b=fs[i].delete();
						
					}
				}
			}
			
		}
		
		return b;
	}
	
	/**
	 * purpose 用于递归清楚整个目录或者文件
	 * @param f
	 */
	public void deleteFiles(File f)
	{
		
			if(f.isDirectory())
			{
				File [] fs=f.listFiles();
				for(int i=0;i<fs.length;i++)
				{
					deleteFiles(fs[i]);
				}
			}
			f.delete();
		
	}
	
	/**
	 * purpose 用于生成文件或者目录，并复制其中文件的内容
	 * @param f 被剪切或者复制的文件 
	 * @param d 目标文件夹：即是被粘贴在这个目录下
	 */
	public void copyFiles(File f,File d)
	{
		d=new File(d,f.getName());//在目标路径创建相应的文件或者目录
		if(f.isDirectory())
		{
			d.mkdir();
			File [] fs=f.listFiles();
			for(int i=0;i<fs.length;i++)
			{
				this.copyFiles(fs[i], d);
			}
		}
		else
		{
			byte [] bt=new byte[8192];
			FileInputStream fis=null;
			FileOutputStream fos=null;
			try {
				fis=new FileInputStream(f);
				fos=new FileOutputStream(d);
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			try 
			{
				while(fis.read(bt)!=-1)
				{
					fos.write(bt);
				}
				fis.close();
				fos.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		
	}
	
	/**
	 * purpose 压缩文件并输出到指定的输出流
	 * @param ps 抽象路径名字符串
	 * @param os 输出流
	 */
	public void zip(String ps[],OutputStream os)
	{
		ZipOutputStream zos=new ZipOutputStream(os);
		zos.setComment("欢迎使用小菜毛毛远程管理 \r\n \r\n作者:caizhh2009@gmail.com");
		for(int i=0;i<ps.length;i++)
		{
			try {
				this.zip(zos, new File(URLDecoder.decode(ps[i],"utf-8")), "");
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		
		try 
		{
			zos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**
	 * purpse 压缩文件或者文件夹
	 * @param zos 
	 * @param f
	 * @param context
	 */
	public void zip(ZipOutputStream zos,File f,String context)
	{
		String n=f.getName();
		Long lt=f.lastModified();
		
		if(f.isDirectory())
		{
			context=context + n + "/";//设置路径名比如：aaa/ddd;
		    ZipEntry ze=new ZipEntry(context);//使用目录名称创建新的 ZIP 条目
		    ze.setTime(lt);//设置条目的修改时间
		    try {
				zos.putNextEntry(ze);//写入条目到输出流指定的zip文件中
				zos.closeEntry();//关闭当前 ZIP 条目并定位流以写入下一个条目并将流定位到条目数据的开始处
			} catch (IOException e) {
				e.printStackTrace();
			}
			File[] fs = f.listFiles();
			for(int i=0;i<fs.length;i++)
			{
				this.zip(zos, fs[i], context);
			}
		    
		}
		else if(f.isFile())
		{
			int i=0;
			byte [] b=new byte[8192];
			FileInputStream is=null;
			ZipEntry ze=new ZipEntry(context+n);
			ze.setTime(lt);
			try {
				zos.putNextEntry(ze);//写入条目到输出流指定的zip文件中并将流定位到条目数据的开始处
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			 try {
				is=new FileInputStream(f);
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			try {
				while(is.read(b)!=-1)
				{

				}
				is.close();
				zos.closeEntry();
				
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
		}
	}
	/**
	 * purpose 解压文件
	 * @param file 需要解压的文件
	 * @param dir 目标路径
	 * @return
	 */
	
	public String unZip(File file,File dir)
	{
		if(file.getName().toLowerCase().endsWith(".zip"))
		{
			StringBuffer result=new StringBuffer();
			ZipFile zf =null;
			try {
				zf=new ZipFile(file);
				
			} catch (ZipException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			Enumeration e=zf.entries();
			while(e.hasMoreElements())
			{
				ZipEntry ze=(ZipEntry)e.nextElement();//获取压缩文件条目
				String zname=ze.getName();
				result.append(zname);
				File f= new File(dir,zname);//创建文件
				if(ze.isDirectory())
				{
					f.mkdirs();
				}
				else
				{
			        int i=0;
			        byte zeby[] = new byte[8192];
			        InputStream is=null;
			        OutputStream os= null;
			        try {
						is = zf.getInputStream(ze);//获取该条目的输入流（输入流即是输入到程序的流）
						os = new FileOutputStream(f);
						while((i=is.read(zeby))!=-1)
						{
							os.write(zeby);
						}
						is.close();
						os.close();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
					
				}
				  f.setLastModified(ze.getTime());
				  try {
					zf.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			      result.append("全部完成");
			      return result.toString();
			}
			
			return result.toString();
		}
		
		else
		{
			Runtime rt = Runtime.getRuntime();//获取运行环境
			//在C盘或者D盘查找执行程序
		    File f=new File("C:\\Program Files\\WinRAR\\UnRAR.exe");
		    if(!f.exists())f=new File("D:\\Program Files\\WinRAR\\UnRAR.exe");
		    String path=f.exists()?f.getPath():"unrar";
		    Process p = null;
			try {
				p = rt.exec("\"" + path + "\" x -o+ -p- " + file.getAbsolutePath() + " " + dir.getAbsolutePath());//在单独的进程中执行指定命令和变量
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		    StringBuffer sb = new StringBuffer();
		    InputStream fis = p.getInputStream();//获取子进程的输入流
		    int value = 0;
		    try {
				while ((value = fis.read()) != -1)
				{
				  sb.append((char) value);
				}
				fis.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		    
		    String result=null;
			try {
				result = new String(sb.toString().getBytes("ISO-8859-1"), "GBK");
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		    int index = result.indexOf("中解压");
		    if (index == -1)
		    {
		      return (file.getName() + " 不是 RAR 压缩文件");
		    } else
		    {
		      index += 4;
		      result = result.substring(index);
		      result = result.replaceAll("\r\n", "<br/>").replaceAll("  ", "　");//.replaceAll("\n", "<BR/>").replaceAll("\\\\", "/").replaceAll(file.getAbsolutePath(), "");
		      return (result);
		    }
		}
	}
	
	
	

}
